﻿using System;
using System.Collections;
using System.Threading;

namespace TrueCode.Core.Diagnostics
{
	public static class ExceptionHelper
	{
		private static int _exceptionIdCounter;

		public static int GetExceptionId()
		{
			return Interlocked.Increment(ref _exceptionIdCounter);
		}

		public static void ThrowIfArgumentIsNull<TExceptionSpecialization>(Object argument, String argumentName)
		{
			ThrowIfArgumentIsNull<TExceptionSpecialization>(argument, argumentName, null);
		}

		public static void ThrowIfArgumentIsNull<TExceptionSpecialization>(
			Object argument, String argumentName, String message)
		{
			if(!DebugAssert.IsNotNull(argument, message))
			{
				throw new Exception<TExceptionSpecialization, ArgumentNullException>(
					GetExceptionId(), new ArgumentNullException(argumentName, message));
			}
		}

		public static void ThrowIfArgumentIsNullOrEmpty<TExceptionSpecialization>(String argument, String argumentName)
		{
			ThrowIfArgumentIsNullOrEmpty<TExceptionSpecialization>(argument, argumentName, null);
		}

		public static void ThrowIfArgumentIsNullOrEmpty<TExceptionSpecialization>(
			String argument, String argumentName, String message)
		{
			if(!DebugAssert.IsFalse(String.IsNullOrEmpty(argument)))
			{
				throw new Exception<TExceptionSpecialization, ArgumentNullException>(
					GetExceptionId(), new ArgumentNullException(argumentName, message));
			}
		}

		public static void ThrowIfArgumentIsNullOrEmpty<TExceptionSpecialization>(ICollection argument, String argumentName)
		{
			ThrowIfArgumentIsNullOrEmpty<TExceptionSpecialization>(argument, argumentName, null);
		}

		public static void ThrowIfArgumentIsNullOrEmpty<TExceptionSpecialization>(
			ICollection argument, String argumentName, String message)
		{
			if(!(DebugAssert.IsNotNull(argument) && DebugAssert.IsTrue(argument.Count > 0)))
			{
				throw new Exception<TExceptionSpecialization, ArgumentNullException>(
					GetExceptionId(), new ArgumentNullException(argumentName, message));
			}
		}

		public static Exception<T> CreateException<T>(string message)
		{
			return new Exception<T>(GetExceptionId(), message);
		}

		public static Exception<T, TSpecialization> CreateException<T, TSpecialization>()
		{
			return new Exception<T, TSpecialization>(GetExceptionId());
		}

		public static Exception<T, TSpecialization> CreateException<T, TSpecialization>(Exception innerException)
		{
			return new Exception<T, TSpecialization>(GetExceptionId(), innerException);
		}

		public static Exception<T, TSpecialization> CreateException<T, TSpecialization>(Exception innerException, string message)
		{
			return new Exception<T, TSpecialization>(GetExceptionId(), innerException, message);
		}

		public static Exception<T, TSpecialization> CreateException<T, TSpecialization>(string message)
		{
			return new Exception<T, TSpecialization>(GetExceptionId(), message);
		}
	}
}
